/* eslint-disable react/prop-types */
import React from 'react';
import { Button, Field, Form, Input, DatePicker, Checkbox, Message, Tree } from '@teamix/ui';
import intl from 'components/PersonalSettings/components/locale';
import Icon from 'components/PersonalSettings/components/icon';
import { updateToken, generateToken } from 'components/PersonalSettings/components/utils/api/index';
import dayjs from 'dayjs';

const prefix = 'personal-access-token-form';
export default class SelectScope extends React.Component {
  constructor(props) {
    super(props);
    this.field = new Field(this);
    const { data, selectedScopes } = this.initData(props);
    this.state = {
      submitting: false,
      data,
      selectedScopes,
    };
  }

  initData = (props) => {
    if (!props.data) {
      return {
        data: {},
        selectedScopes: [],
      };
    }
    const data = {
      ...props.data,
      expire: props.data.expire_time || '',
    };
    const arr = props.data.scope.split(',');
    const { scopes } = props;
    scopes.forEach((item) => {
      // admin:repo=repo 后端返回多带了文字admin:
      const index = arr.indexOf(`admin:${item.scope}`);
      if (index > -1 && item.sub_scopes && item.sub_scopes.length) {
        const newItem = item.sub_scopes.map((sub) => sub.scope);
        arr.splice(index, 1, ...newItem);
      }
    });
    return {
      data,
      selectedScopes: arr,
    };
  };

  handleCancel = () => {
    const { onClose } = this.props;
    onClose && onClose();
  };

  handleSubmit = () => {
    const { submitting, selectedScopes, data } = this.state;
    if (submitting) return;
    this.setScopeError(selectedScopes);
    this.field.validate((errors) => {
      if (!errors) {
        const formData = this.field.getValues();
        const curScope = this.getTreeCurScope();
        formData.scope = curScope;
        formData.expire = data.expireChanged
          ? `${data.expire} 23:59:59`
          : dayjs(data.expire).format('YYYY-MM-DD HH:mm:ss');

        this.setState({ submitting: true });
        this.submitForm(formData);
      }
    });
  };

  submitForm = (formData) => {
    const { type, onOk, data, onClose } = this.props;
    const promise =
      type === 'edit'
        ? updateToken(data.id, formData, this.props.vpc)
        : generateToken(formData, this.props.vpc);
    promise
      .then((res) => {
        if (res.success || res.id) {
          this.setState({ submitting: false });
          const resValue = this.props.vpc ? res.data : res;
          // 编辑不会返回newToken
          onOk && onOk(type === 'edit' ? null : resValue);
          onClose && onClose();
        } else {
          this.setState({ submitting: false }, () => {
            Message.error({
              title: res?.result?.message || '创建失败',
            });
          });
        }
      })
      .catch((err) => {
        this.setState({ submitting: false });
        try {
          const errCause = err.errData.message;
          Message.error({
            title: errCause,
          });
        } catch (e) {
          console.error(e);
        }
      });
  };

  getCurScope = () => {
    const { selectedScopes } = this.state;
    const { scopes } = this.props;
    // 如果子节点全部被选中，则将父节点的scope传给后端
    if (!scopes.length) {
      return '';
    }
    const arr = [...selectedScopes];
    scopes.forEach((item) => {
      const { sub_scopes } = item;
      if (sub_scopes) {
        const isAllSelected = sub_scopes.every((sub) => {
          return arr.includes(sub);
        });
        if (isAllSelected) {
          sub_scopes.forEach((sub) => {
            const index = arr.indexOf(sub.scope);
            arr.splice(index, 1);
          });
        }
      }
    });

    return arr.join();
  };

  handleSelectScope = (value, item) => {
    const { selectedScopes } = this.state;
    if (item.sub_scopes && item.sub_scopes.length) {
      item.sub_scopes.forEach((sub) => {
        if (value && !selectedScopes.includes(sub.scope)) {
          selectedScopes.push(sub.scope);
        }
        if (!value) {
          const index = selectedScopes.indexOf(sub.scope);
          if (index > -1) {
            selectedScopes.splice(index, 1);
          }
        }
      });
    } else {
      if (value && !selectedScopes.includes(item.scope)) {
        selectedScopes.push(item.scope);
      }
      if (!value) {
        const index = selectedScopes.indexOf(item.scope);
        if (index > -1) {
          selectedScopes.splice(index, 1);
        }
      }
    }
    this.setState({
      selectedScopes,
    });
    this.setScopeError(selectedScopes);
  };

  getCheckboxStatus = (item) => {
    const { selectedScopes } = this.state;
    if (!item.sub_scopes || !item.sub_scopes.length) {
      return {
        checked: selectedScopes.includes(item.scope),
        indeterminate: false,
      };
    } else {
      const checked =
        item.sub_scopes.length > 0 &&
        item.sub_scopes.every((sub) => {
          return selectedScopes.includes(sub.scope);
        });
      const hasOneKey =
        item.sub_scopes.length > 0 &&
        item.sub_scopes.some((sub) => {
          return selectedScopes.includes(sub.scope);
        });
      return {
        checked,
        indeterminate: !checked && hasOneKey,
      };
    }
  };

  setScopeError = (keys) => {
    this.field.setError('scope', keys.length ? '' : '该项为必填项');
  };

  renderScope = () => {
    const { scopes } = this.props;
    const { selectedScopes } = this.state;
    return (
      <div className={`${prefix}-scope`}>
        {scopes.map((item) => {
          const sub_scopes = item.sub_scopes || [];
          const statuses = this.getCheckboxStatus(item);
          return (
            <div className="scope-item">
              <div className="scope-item-parent">
                <div className="scope-item-label">
                  <Checkbox
                    checked={statuses.checked}
                    indeterminate={statuses.indeterminate}
                    onChange={(checked) => {
                      this.handleSelectScope(checked, item);
                    }}
                  >
                    {item.scope}
                  </Checkbox>
                </div>
                <div className="scope-item-desc">{item.description}</div>
              </div>
              {sub_scopes.map((sub) => {
                return (
                  <div className="scope-item-child">
                    <div className="scope-item-label">
                      <Checkbox
                        checked={selectedScopes.includes(sub.scope)}
                        onChange={(checked) => {
                          this.handleSelectScope(checked, sub);
                        }}
                      >
                        {sub.scope}
                      </Checkbox>
                    </div>
                    <div className="scope-item-desc">{sub.description}</div>
                  </div>
                );
              })}
            </div>
          );
        })}
      </div>
    );
  };

  disabledDate = (date) => {
    return date.valueOf() <= dayjs().valueOf();
  };

  // eslint-disable-next-line no-unused-vars
  onCheckSelectTree = (checkedKeys, _extra) => {
    this.setState({
      selectedScopes: checkedKeys,
    });
  };

  getTreeCurScope = () => {
    const { selectedScopes } = this.state;
    const arrayFilter = selectedScopes.filter((va) => {
      return this.getScopesIsExistChildren(va);
    });
    const value = arrayFilter.join(',');
    return value;
  };

  getScopesIsExistChildren = (type) => {
    const { scopes } = this.props;
    let flag = false;
    const isExisChildren = (array, name) => {
      if (array?.length <= 0) return false;
      array.forEach((item) => {
        if (item.key === name && item.children && item.children.length > 0) {
          flag = false;
        } else if (item.key === name && item.children && item.children.length === 0) {
          flag = true;
        } else if (item.children && item.children.length > 0) {
          return isExisChildren(item.children, name);
        }
      });
    };
    isExisChildren(scopes, type);
    return flag;
  };

  render() {
    const { type, scopes } = this.props;
    const { init } = this.field;
    const { data, selectedScopes } = this.state;
    const isEdit = type === 'edit';
    const { name = '', expire = '' } = data;
    return (
      <div className={prefix}>
        <div className={`${prefix}-title`}>
          {intl.get(isEdit ? 'personal_access_token_edit' : 'personal_access_token_create')}
        </div>
        <Form field={this.field}>
          <Form.Item label={intl.get('name')} required>
            <Input
              {...init('name', {
                initValue: name,
                rules: [{ required: true, message: intl.get('item_necessary') }],
              })}
              style={{ width: 220 }}
              placeholder={intl.get('please_input_name')}
            />
          </Form.Item>
          <Form.Item label={intl.get('outdated_time')} required>
            <DatePicker
              disabledDate={this.disabledDate}
              {...init('expire', {
                initValue: expire ? dayjs(expire).format('YYYY-MM-DD') : '',
                rules: [{ required: true, message: intl.get('item_necessary') }],
                props: {
                  onChange: (v) => {
                    this.setState({
                      data: {
                        ...data,
                        expire: v.replace('年', '-').replace('月', '-').replace('日', ''),
                      },
                    });
                  },
                },
              })}
            />
          </Form.Item>
          <Form.Item
            label={intl.get('personal_access_token_range')}
            required
            className={this.field.getState('scope') === 'error' ? 'has-error' : ''}
            help={
              this.field.getState('scope') === 'error' ? (
                <div>
                  <Icon type="remove-o-fill" />
                  <span className="next-form-item-help-text">{this.field.getError('scope')}</span>
                </div>
              ) : (
                ''
              )
            }
          >
            {/* {this.renderScope()} */}
            <div className="select_scopen_tree">
              <Tree
                checkable
                editable
                selectable={false}
                dataSource={scopes}
                defaultCheckedKeys={selectedScopes?.length > 0 ? selectedScopes : []}
                defaultExpandedKeys={['user', 'repo', 'org', 'group']}
                onCheck={this.onCheckSelectTree}
              />
            </div>
          </Form.Item>
        </Form>
        <div className={`${prefix}-btns`}>
          <Button type="primary" onClick={this.handleSubmit} loading={this.state.submitting}>
            {intl.get(isEdit ? 'update_now' : 'create_now')}
          </Button>
          <Button type="normal" onClick={this.handleCancel} style={{ marginLeft: 20 }}>
            {intl.get('cancel')}
          </Button>
        </div>
      </div>
    );
  }
}
